/* Copyright (C) 2010 Moritz Bitsch
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 *      Moritz Bitsch <moritzbitsch@googlemail.com>
 */

namespace Webappi {
	public class Application {
		private HashTable<string, IHandler> paths;

		public Application() {
			paths = new HashTable<string, IHandler>(str_hash,str_equal);
		}

		public void addPath(string path_regex, IHandler handler) {
			dprint(LogLevel.Debug, "MAIN", "Adding Handler for %s".printf(path_regex));
			paths.insert(path_regex, handler);
		}

		private void send_status(scgi.Request req, int status) {
			//FIXME: Custom error pages?
			var line = "Status: %d\r\n\r\n".printf(status);
			req.output.write(line, line.length, null);
		}

		private void requestHandler(scgi.Request req) {
			IHandler handler = null;
			string[] parameter = null;
			MatchInfo info = null;

			//cleanup our session store
			Session.cleanup();

			foreach (string key in paths.get_keys()) {
				GLib.Regex regex;
				try {
					regex = new GLib.Regex(key);
					var tmpUri = req.params.lookup("REQUEST_URI");
					if (regex.match(tmpUri, 0, out info)) {
						dprint(LogLevel.Insane, "REGEXING", "match: %s | %s".printf(key, tmpUri));
						handler = paths.lookup(key);
						parameter = info.fetch_all();
						break;
					} else {
						dprint(LogLevel.Insane, "REGEXING", "Did not match: %s | %s".printf(key, tmpUri));
					}
				} catch (GLib.RegexError e) {
					dprint(LogLevel.Silent, "REGEXING", "Can't compile regex(%s): %s".printf(key, e.message));
					send_status(req, 500);
				}
			}

			if (handler != null) {
				var method = req.params.lookup("REQUEST_METHOD");
				Result res = null;
				switch (method) {
				case "POST":
					dprint(LogLevel.Insane, "LOOP", "got post request");
					res = handler.POST(req, parameter);
					break;
				case "GET":
					dprint(LogLevel.Insane, "LOOP", "got get request");
					res = handler.GET(req, parameter);
					break;
				default:
					send_status(req, 400);
					break;
				}

				if (res != null) {
					foreach (string header in res.header) {
						var line = "%s\r\n".printf(header).to_utf8();
						req.output.write(line, line.length, null);
					}

					var status = "Status: %d\r\n".printf(res.status).to_utf8();
					req.output.write(status, status.length, null);

					var ctype = "Content-type: %s\r\n\r\n".printf(res.contentType).to_utf8();
					req.output.write(ctype, ctype.length, null);

					var data = res.result;
					req.output.write(data, data.length, null);
				}
			} else {
				dprint(LogLevel.Debug, "LOOP", "no handler");
				send_status(req, 404);
			}
		}

		public int run(uint16 port, int maxThreads) {
			new scgi.Server(port, maxThreads, requestHandler);
			return 0;
		}
	}
}
